﻿using CleanArchitecture.Core.Events;
using CleanArchitecture.Core.Interfaces;
using CleanArchitecture.Core.Interfaces.Cache;
using CleanArchitecture.Infrastructure.Configuration;
using CleanArchitecture.Infrastructure.Entities;
using CleanArchitecture.Infrastructure.Entities.Business;
using CleanArchitecture.Infrastructure.Interfaces;
using CleanArchitecture.Infrastructure.Interfaces.Business;
using CleanArchitecture.Infrastructure.Models.Business.Columns;
using CleanArchitecture.Infrastructure.Services.DatabaseProvider;
using System;
using System.Collections.Generic;
using System.Linq;

namespace CleanArchitecture.Infrastructure.Services.Business
{
    public partial class ColumnService : IColumnService
    {
        #region Fields
        private readonly IStaticCacheManager _cacheManager;
        private readonly IRepository<Column> _columnRepository;
        private readonly IDomainEventDispatcher _eventDispatcher;
        private readonly IRepository<Language> _languageRepository;
        private readonly IRepository<AdminRoleBusColumnMapping> _rolecolumnMappingRepository;
        private readonly IDataProvider _dataProvider;
        private readonly IDbContext _dbContext;
        #endregion

        #region Ctor
        public ColumnService(IDomainEventDispatcher eventDispatcher,
            IDbContext dbContext,
            IDataProvider dataProvider,
            IRepository<Column> columnRepo,
            IRepository<Language> languageRepo,
            IRepository<AdminRoleBusColumnMapping> rolecolumnMappingRepo,
            IStaticCacheManager cacheManager)
        {
            this._cacheManager = cacheManager;
            this._eventDispatcher = eventDispatcher;
            this._columnRepository = columnRepo;
            this._languageRepository = languageRepo;
            this._dataProvider = dataProvider;
            this._dbContext = dbContext;
            this._rolecolumnMappingRepository = rolecolumnMappingRepo;
        }
        #endregion

        /// <summary>
        /// Gets All the records of the Website(Frontend) NaviMenu
        /// Categories by Language Group and Set to Cache
        /// </summary>
        /// <returns></returns>
        public IList<ColumnItemModel> GetColumnList()
        {
            string cacheKey = DefaultCacheConfig.ColumnListCacheKeyAll;
            return _cacheManager.Get(cacheKey, () =>
            {
                var columns = from column in _columnRepository.Table
                              where column.IsActive == EntityEnumConfig.YesorNo.YES
                              join language in _languageRepository.Table.Where(l => l.IsActive == EntityEnumConfig.YesorNo.YES)
                              on column.FKLanguageId equals language.Id into tempinnerjoin
                              from j in tempinnerjoin.DefaultIfEmpty()
                              orderby j.DisplayOrder, column.PID, column.DisplayOrder, column.ColumnType
                              select new ColumnItemModel
                              {
                                  Id = column.Id,
                                  LanguageId = j.Id,
                                  LanguageName = j.DisplayName,
                                  LanguageCulture = j.Culture,
                                  LanguageCode = j.LanguageCode,
                                  ParentId = column.PID,
                                  ColumnType = column.ColumnType,
                                  Level = column.Level,
                                  MetaKeyWords = column.MetaKeyWords,
                                  MetaDescription = column.MetaDescription,
                                  MetaTitle = column.MetaTitle,
                                  Name = column.DisplayName,
                                  SubTitle = column.SubTitle,
                                  IsDisplay = column.IsDisplay,
                                  IconImageUrl = column.IconImageUrl,
                                  CoverImageUrl = column.CoverImageUrl,
                                  UrlRoute = column.UrlRoute,
                                  UrlTarget = column.UrlTarget,
                                  PageSize = column.PageSize,
                                  PageSizeOptions = column.PageSizeOptions,
                                  IsActive = column.IsActive,
                                  DisplayOrder = column.DisplayOrder,
                                  LayoutType = column.LayoutType,
                                  LayoutDetailTemplate = column.LayoutDetailTemplate,
                                  LayoutListTemplate = column.LayoutListTemplate
                              };
                return columns.ToList();
            });
        }
        /// <summary>
        /// 测试SQL 按用户角色权限查询对应的栏目菜单
        /// SELECT C.Id,C.PID,C.FK_LanguageId,C.ColumnType,C.DisplayName
        /// FROM bus_column AS C
        /// LEFT JOIN bus_language AS L ON C.FK_LanguageId = L.Id
        /// LEFT JOIN adminrole_buscolumn_mapping AS M ON C.Id = M.FK_BusColumn_Id
        /// WHERE C.IsActive = 1 AND M.FK_AdminRole_Id IN ( 1, 2 )
        /// ORDER BY L.DisplayOrder,C.ColumnType,C.PID,C.DisplayOrder;
        /// </summary>
        /// <param name="roleIds"></param>
        /// <returns></returns>
        public IList<ColumnItemModel> GetColumnListByRoleIds(int[] roleIds)
        {
            string cacheKey = string.Format(DefaultCacheConfig.ColumnListCacheKeyByRoles, string.Join('-', roleIds));
            return _cacheManager.Get(cacheKey, () =>
            {
                var columns = from column in _columnRepository.Table
                              join language in _languageRepository.Table
                              on column.FKLanguageId equals language.Id into tempinnerjoin
                              from j in tempinnerjoin.DefaultIfEmpty()
                              join mapping in _rolecolumnMappingRepository.Table//.Where(m => roleIds.Contains(m.FKAdminRoleId))
                              on column.Id equals mapping.FKColumnId into tempmapping 
                              from auth in tempmapping.DefaultIfEmpty()  
                              where column.IsActive == EntityEnumConfig.YesorNo.YES && j.IsActive == EntityEnumConfig.YesorNo.YES 
                              && auth.IsAllow == EntityEnumConfig.YesorNo.YES && roleIds.Contains(auth.FKAdminRoleId)
                              orderby j.DisplayOrder, column.ColumnType, column.PID, column.DisplayOrder
                              select new ColumnItemModel
                              {
                                  Id = column.Id,
                                  LanguageId = j.Id,
                                  LanguageName = j.DisplayName,
                                  LanguageCulture = j.Culture,
                                  LanguageCode = j.LanguageCode,
                                  ParentId = column.PID,
                                  ColumnType = column.ColumnType,
                                  Level = column.Level,
                                  MetaKeyWords = column.MetaKeyWords,
                                  MetaDescription = column.MetaDescription,
                                  MetaTitle = column.MetaTitle,
                                  Name = column.DisplayName,
                                  SubTitle = column.SubTitle,
                                  IsDisplay = column.IsDisplay,
                                  IconImageUrl = column.IconImageUrl,
                                  CoverImageUrl = column.CoverImageUrl,
                                  UrlRoute = column.UrlRoute,
                                  UrlTarget = column.UrlTarget,
                                  PageSize = column.PageSize,
                                  PageSizeOptions = column.PageSizeOptions,
                                  IsActive = column.IsActive,
                                  DisplayOrder = column.DisplayOrder,
                                  LayoutType = column.LayoutType,
                                  LayoutDetailTemplate = column.LayoutDetailTemplate,
                                  LayoutListTemplate = column.LayoutListTemplate
                              };
                if (columns == null) return null;
                //去重处理
                //columns.GroupBy(item => item.Id).Select(g => distinctList = g.ToList());
                return columns.Distinct().ToList();
            });
        }
        public Column GetColumnById(int cid)
        {
            if (cid == 0) return null;
            return _columnRepository.GetById(cid);
        }

        public void UpdateColumn(Column entity)
        {
            if (entity == null)
                throw new ArgumentNullException(nameof(entity));

            _columnRepository.Update(entity, new string[] { nameof(entity.CreatedOnTimeUtc) });
            _cacheManager.Remove(DefaultCacheConfig.ColumnListCacheKeyAll);
            //event notification
            if (!string.IsNullOrEmpty(entity.SysLogMsg))
                _eventDispatcher.Dispatch(new EntityUpdatedEvent<Column>(entity));
        }

        public void InsertColumn(Column entity)
        {
            if (entity == null)
                throw new ArgumentNullException(nameof(entity));

            _columnRepository.Insert(entity);
            _cacheManager.Remove(DefaultCacheConfig.ColumnListCacheKeyAll);
            //event notification
            if (!string.IsNullOrEmpty(entity.SysLogMsg))
                _eventDispatcher.Dispatch(new EntityInsertedEvent<Column>(entity));
        }
        public void DeleteColumn(Column entity)
        {
            if (entity == null)
                throw new ArgumentNullException(nameof(entity));
            entity.DisplayName = entity.DisplayName + "-Deleted";
            entity.IsActive = EntityEnumConfig.YesorNo.No;
            entity.UpdatedOnTimeUtc = DateTime.UtcNow;
            DeleteColumnRoleMappings(entity.Id);
            this.UpdateColumn(entity);
        }

        #region ColumnAuthorize
        /// <summary>
        /// Get Mapping List by AdminRole Ids
        /// </summary>
        /// <param name="role"></param>
        /// <returns></returns>
        public virtual IList<AdminRoleBusColumnMapping> GetAdminRoleColumnMappingsByRoleIds(int[] roleIds)
        {
            if (roleIds == null || roleIds.Length == 0) return null;
            return _rolecolumnMappingRepository.TableNoTracking.Where(m => roleIds.Contains(m.FKAdminRoleId)).ToList();
        }
        /// <summary>
        /// 新增用户角色对应栏目模块权限
        /// </summary>
        /// <param name="mappings"></param>
        public virtual void InsertAdminRoleColumnAuthorize(IList<AdminRoleBusColumnMapping> mappings)
        {
            if (mappings == null || mappings.Count == 0)
                throw new ArgumentNullException(nameof(mappings));
            _rolecolumnMappingRepository.Insert(mappings);
            _eventDispatcher.Dispatch(new EntityInsertedEvent<AdminRoleBusColumnMapping>(mappings.First()));
        }
        /// <summary>
        /// 更新用户角色对应系统模块权限
        /// </summary>
        /// <param name="mappings"></param>
        public virtual void UpdateAdminRoleColumnAuthorize(IList<AdminRoleBusColumnMapping> mappings)
        {
            if (mappings == null || mappings.Count == 0)
                throw new ArgumentNullException(nameof(mappings));
            _rolecolumnMappingRepository.Update(mappings);
            _eventDispatcher.Dispatch(new EntityUpdatedEvent<AdminRoleBusColumnMapping>(mappings.First()));
        }
        //DavidLee 2020/07/31 增加对栏目权限控制的Mapping表删除功能
        protected void DeleteColumnRoleMappings(int cid)
        {
            //prepare parameters
            var pColumnId = _dataProvider.GetInt32Parameter("columnId", cid);

            //invoke stored procedure
            _dbContext.ExecuteSqlCommand("CALL DeleteColumnRoleMappings(@columnId)",
                false, null, pColumnId);
        }
        #endregion
    }
}
